﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Simulacion.NumberGenerator;

namespace Simulacion.Distributions
{
    /// <summary>
    ///  Generic class of the Lognormal3P distribution.
    /// </summary>
    class Lognormal3P
    {

        public static double lognormal_3P_f(double x, double mi, double sigma, double gamma)
        {
            return Math.Exp(-0.5 * Math.Pow((Math.Log(x - gamma) - mi) / sigma, 2.0)) / ((x - gamma) * sigma * Math.Sqrt(2.0 * Math.PI));
        }

        public static double cumulative_lognormal_3P_f(double a, double b, int n, double mi, double sigma, double gamma)
        {
            double h;
            h = (b - a) / ((double)n);

            double x = 0, sum = 0;
            sum = lognormal_3P_f(a, mi, sigma, gamma) + lognormal_3P_f(b, mi, sigma, gamma);
            x = a + h;
            for (int i = 1; i <= n - 1; i++, x += h) sum += 2.0 * lognormal_3P_f(x, mi, sigma, gamma);

            return h * sum / 2.0;
        }

        public static double bsLognormal3P(double expected, double minx, double lower, double upper, double mi, double sigma, double gamma, int overflow)
        {
            double mean = (upper + lower) / 2.0;
            double fmean = cumulative_lognormal_3P_f(minx, mean, 100, mi, sigma, gamma);

            if (Math.Abs(expected - fmean) < 0.0000001 || overflow < 0) return mean;

            if (expected > fmean) return bsLognormal3P(expected, minx, mean, upper, mi, sigma, gamma, overflow - 1);
            else return bsLognormal3P(expected, minx, lower, mean, mi, sigma, gamma, overflow - 1);
        }

        public static double fLognormal3P(double x, double mi, double sigma, double gamma)
        {
            return (Math.Exp(-0.5 * Math.Pow((Math.Log(x - gamma) - mi) / sigma, 2.0)) / ((x - gamma) * sigma * Math.Sqrt(2.0 * Math.PI)));
        }

        /// <summary>
        /// Gets the value using the Lognormal3P distribution.
        /// </summary>
        /// <returns>The value of the distribution.</returns>
        public static double GetDistributionValue(double lower, double upper, double mi, double sigma, double gamma)
        {
            double R = Generator.NextNumber;
            return bsLognormal3P(R, lower, lower, upper, mi, sigma, gamma, 100) / 7;
        }
    }
}
